package com.yk.system.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileTypeUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.yk.api.system.dto.DeviceDTO;
import com.yk.api.system.dto.GatewayDTO;
import com.yk.common.core.constant.CacheConstants;
import com.yk.common.core.constant.Constants;
import com.yk.common.core.constant.NumberConstant;
import com.yk.common.core.domain.BasePageQuery;
import com.yk.common.core.domain.LoginUser;
import com.yk.common.core.domain.PageResult;
import com.yk.common.core.domain.Result;
import com.yk.common.core.exception.user.UserException;
import com.yk.common.core.utils.LoginHelper;
import com.yk.common.excel.core.ExcelRecord;
import com.yk.common.excel.core.ExcelResult;
import com.yk.common.excel.utils.ExcelUtil;
import com.yk.common.log.annotation.Log;
import com.yk.common.log.constant.LogConstants;
import com.yk.common.log.enums.BusinessType;
import com.yk.common.rabbitmq.constant.QueueConstants;
import com.yk.common.redis.service.RedisService;
import com.yk.system.convert.DeviceConvert;
import com.yk.system.convert.GatewayConvert;
import com.yk.system.entity.Card;
import com.yk.system.entity.Device;
import com.yk.system.entity.Gateway;
import com.yk.system.service.*;
import com.yk.system.service.readImpl.GateWayReadImpl;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 网关管理 yk-system
 *
 * @author lmx
 * @date 2023/10/16 18:15
 */
@Slf4j
@Api(tags = "网关管理")
@RestController
@RequiredArgsConstructor
@RequestMapping("/gateWay")
public class GateWayController {

    private final GatewayService gatewayService;
    private final CardService cardService;
    private final DeviceService deviceService;
    private final GroupDeviceService groupDeviceService;
    private final GatewayConvert gatewayConvert;
    private final DeviceConvert deviceConvert;
    private final RedisService redisService;
    private final GateWayReadImpl gateWayReadImpl;
    private final AmqpTemplate amqpTemplate;

    @Log(title = "网关", businessType = BusinessType.INSERT)
    @ApiOperation("新增")
    @PostMapping("/add")
    public Result<Void> add(@Validated @RequestBody GatewayDTO dto) {
        String number = dto.getNumber();
        long count = gatewayService.count(new LambdaQueryWrapper<Gateway>()
                .eq(Gateway::getNumber, number).or().eq(Gateway::getTopic, dto.getTopic()));
        if (count > 0L) {
            return Result.fail("该网关已被使用");
        }
        Assert.notEmpty(dto.getTopic(), "主题不能为空");
        Long gatewayId = IdWorker.getId();
        dto.setId(gatewayId);
        gatewayService.save(gatewayConvert.dto2Entity(dto));
        redisService.setCacheObject(CacheConstants.GATEWAY_KEY + dto.getTopic(), dto);
        if (CharSequenceUtil.isNotEmpty(dto.getCardNumber())) {
            Card card = cardService.saveCard(dto.getCardNumber(), NumberConstant.ONE_STR);
            amqpTemplate.convertAndSend(QueueConstants.SEARCH_CARD, card);
        }
        return Result.ok2Log(LogConstants.ADD + dto.getName());
    }

    @Log(title = "网关", businessType = BusinessType.UPDATE)
    @ApiOperation("编辑")
    @PostMapping("/edit")
    public Result<Void> edit(@Validated @RequestBody GatewayDTO dto) {
        String number = dto.getNumber();
        LambdaQueryWrapper<Gateway> lambda = new LambdaQueryWrapper<>();
        lambda.ne(Gateway::getId, dto.getId());
        lambda.and(it -> {
            it.eq(Gateway::getNumber, number);
            it.or();
            it.eq(Gateway::getTopic, dto.getTopic());
        });
        long count = gatewayService.count(lambda);
        if (count > 0L) {
            return Result.fail("该网关已被使用");
        }
        redisService.setCacheObject(CacheConstants.GATEWAY_KEY + dto.getTopic(), dto);
        gatewayService.updateById(gatewayConvert.dto2Entity(dto));
        if (CharSequenceUtil.isNotEmpty(dto.getCardNumber())) {
            Card card = cardService.saveCard(dto.getCardNumber(), NumberConstant.ONE_STR);
            amqpTemplate.convertAndSend(QueueConstants.SEARCH_CARD, card);
        }
        return Result.ok2Log(LogConstants.UPDATE + dto.getName());
    }

    @Log(title = "网关", businessType = BusinessType.DELETE)
    @ApiOperation("删除")
    @GetMapping("/deleteById/{id}")
    public Result<Void> delete(@PathVariable Long id) {
        Gateway gateway = gatewayService.getById(id);
        if (Objects.isNull(gateway)) {
            return Result.fail("网关不存在");
        }
        gatewayService.removeById(id);
        redisService.deleteObject(CacheConstants.GATEWAY_KEY + gateway.getTopic());
        return Result.ok2Log(LogConstants.DELETE + gateway.getName());
    }

    @ApiOperation("查看")
    @PostMapping("/view")
    public Result<Gateway> view(@RequestBody GatewayDTO dto) {
        return Result.data(gatewayService.getById(dto.getId()));
    }

    @ApiOperation("分页查询")
    @PostMapping("/page")
    public PageResult<GatewayDTO> page(@RequestBody BasePageQuery<GatewayDTO> pageParam) {
        pageParam.getParam().setCreatedBy(LoginHelper.getLoginUserId());
        IPage<GatewayDTO> page = gatewayService.queryPage(pageParam).convert(gatewayConvert::entity2Dto);
        if (CollUtil.isNotEmpty(page.getRecords())) {
            page.getRecords().forEach(it -> {
                List<Device> list = deviceService.list(new LambdaQueryWrapper<Device>().eq(Device::getGatewayId, it.getId()));
                List<DeviceDTO> dtoList = list.stream().map(deviceConvert::entity2Dto).collect(Collectors.toList());
                it.setDeviceDTOList(dtoList);
            });
        }
        return PageResult.success(page.getRecords(), page.getTotal());
    }

    @ApiOperation("全量查询")
    @PostMapping("/list")
    public Result<List<Gateway>> list() {
        LambdaQueryWrapper<Gateway> lambda = new LambdaQueryWrapper<>();
        lambda.eq(Gateway::getCreatedBy, LoginHelper.getLoginUserId());
        List<Gateway> list = gatewayService.list(lambda);
        return Result.data(list);
    }

    @ApiOperation("根据编号查询网关")
    @PostMapping("/selectByNum")
    public Result<GatewayDTO> selectByNum(@RequestParam String number) {
        Gateway gateway = gatewayService.getOne(new LambdaQueryWrapper<Gateway>().eq(Gateway::getNumber, number));
        if (Objects.isNull(gateway)) {
            return Result.fail();
        }
        return Result.data(gatewayConvert.entity2Dto(gateway));
    }

    @ApiOperation("根据编号查询流量卡")
    @PostMapping("/selectCCIDByNum")
    public Result<String> selectCCIDByNum(@RequestParam String number) {
        Gateway gateway = gatewayService.getOne(new LambdaQueryWrapper<Gateway>().eq(Gateway::getNumber, number));
        if (Objects.isNull(gateway) || StrUtil.isEmpty(gateway.getCardNumber())) {
            return Result.ok();
        }
        return Result.data(gateway.getCardNumber());
    }

    @ApiOperation("根据id查询当前数据所在页码")
    @PostMapping("/getPageNum")
    public Result<Integer> getPageNum(@RequestBody BasePageQuery<GatewayDTO> pageParam) {
        GatewayDTO param = pageParam.getParam();
        if (Objects.isNull(param) || Objects.isNull(param.getId())) {
            return Result.data(NumberConstant.ZERO);
        }
        Gateway gateway = gatewayService.getById(param.getId());
        if (Objects.isNull(gateway)) {
            return Result.data(NumberConstant.ZERO);
        }
        return Result.data(gatewayService.getPageNum(param.getId(), pageParam.getPageSize()));
    }

    @PostMapping("/getAppByGroupId")
    @ApiOperation("小程序根据场景Id查询网关列表")
    public Result<List<Gateway>> getAppByGroupId(@RequestBody GatewayDTO param) {
        List<DeviceDTO> dtoList;
        if (0L == param.getGroupId()) {
            dtoList = deviceService.selectNoGroup2Device();
        } else {
            dtoList = groupDeviceService.listByGroupId(param.getGroupId(), LoginHelper.getLoginUserId());
        }
        if (CollUtil.isEmpty(dtoList)) {
            return Result.data(CollUtil.newArrayList());
        }
        List<Long> gateWayIds = dtoList.stream().map(DeviceDTO::getGatewayId).collect(Collectors.toList());
        if (CollUtil.isEmpty(gateWayIds)) {
            return Result.data(CollUtil.newArrayList());
        }
        LambdaQueryWrapper<Gateway> lambda = new LambdaQueryWrapper<>();
        lambda.eq(Objects.nonNull(param.getStatus()), Gateway::getStatus, param.getStatus());
        lambda.like(StrUtil.isNotEmpty(param.getName()), Gateway::getName, param.getName());
        lambda.in(Gateway::getId, gateWayIds);
        List<Gateway> gateWayList = gatewayService.list(lambda);
        return Result.data(gateWayList);
    }

    @ApiOperation("导入模版")
    @GetMapping("/exportTemplate")
    public void exportTemplate(HttpServletResponse response) {
        List<Gateway> list = CollUtil.newArrayList();
        Gateway gateway = new Gateway();
        gateway.setName("网关名称");
        gateway.setNumber("网关编号");
        gateway.setTopic("网关主题-必须以/data结尾");
        gateway.setCardNumber("网关物联网卡号");
        list.add(gateway);
        ExcelUtil.exportExcel(list, "网关模版", Gateway.class, response);
    }

    @ApiOperation("导入")
    @PostMapping("/importExcel")
    public Result<ExcelResult<Gateway>> importExcel(MultipartFile file) throws IOException {
        String type = FileTypeUtil.getType(file.getInputStream(), file.getOriginalFilename());
        Assert.isTrue(StrUtil.equals(type, Constants.XLS) || StrUtil.equals(type, Constants.XLSX), "附件格式错误，请重新上传正确格式的附件");
        ExcelResult<Gateway> excelResult = ExcelUtil.importExcel(file.getInputStream(), Gateway.class, gateWayReadImpl);
        if (CollUtil.isNotEmpty(excelResult.getList())) {
            List<ExcelRecord<Gateway>> collect = excelResult.getList().stream().filter(it -> StrUtil.isNotEmpty(it.getErrorMsg())).collect(Collectors.toList());
            excelResult.setList(collect);
        }
        return Result.data(excelResult);
    }

    @ApiOperation("导出")
    @GetMapping("/export")
    public void export(HttpServletResponse response, GatewayDTO dto) {
        if (Objects.isNull(dto) || StrUtil.isEmpty(dto.getToken())) {
            return;
        }
        LoginUser loginUser = LoginHelper.getLoginUser(dto.getToken());
        if (Objects.isNull(loginUser)) {
            return;
        }
        LambdaQueryWrapper<Gateway> lambda = new LambdaQueryWrapper<>();
        lambda.eq(Gateway::getCreatedBy, loginUser.getUserId());
        lambda.eq(Objects.nonNull(dto.getStatus()), Gateway::getStatus, dto.getStatus());
        if (StrUtil.isNotEmpty(dto.getQ())) {
            lambda.like(Gateway::getName, dto.getQ()).or().like(Gateway::getNumber, dto.getQ());
        }
        lambda.orderByDesc(Gateway::getCreatedAt);
        AtomicInteger index = new AtomicInteger(1);
        List<GatewayDTO> list = Optional.ofNullable(gatewayService.list(lambda)).orElse(CollUtil.newArrayList())
                .stream()
                .map(it -> {
                    GatewayDTO gatewayDTO = gatewayConvert.entity2Dto(it);
                    gatewayDTO.setIndex(index.getAndIncrement());
                    return gatewayDTO;
                })
                .collect(Collectors.toList());
        ExcelUtil.exportExcel(list, "数据", "网关", GatewayDTO.class, response);
    }

    @ApiOperation("根据网关编号查询网关型号")
    @GetMapping("/getModelByNumber/{number}")
    public Result<String> export(@PathVariable("number") String number) {
        Gateway gateway = gatewayService.getOne(new LambdaQueryWrapper<Gateway>().eq(Gateway::getNumber, number));
        if (Objects.isNull(gateway) || StrUtil.isEmpty(gateway.getModel())) {
            return Result.ok();
        }
        return Result.data(gateway.getModel());
    }

    @ApiOperation("网关转让")
    @PostMapping("/transfer")
    @Log(title = "网关", businessType = BusinessType.TRANSFER)
    public Result<Void> transfer(@RequestBody GatewayDTO dto) {
        Assert.notNull(dto.getId(), "网关id不能为空");
        Assert.notEmpty(dto.getName(), "网关名称不能为空");
        Assert.notEmpty(dto.getPhone(), "转让人账号不能为空");
        LoginUser loginUser = LoginHelper.getLoginUser();
        String username = loginUser.getUsername();
        if (username.equals(dto.getPhone())) {
            throw new UserException("无法转让给当前账户");
        }
        try {
            gatewayService.transfer(dto.getId(), dto.getPhone());
        } catch (Exception e) {
            log.error("网关转让失败", e.getMessage());
            return Result.fail("网关转让失败");
        }
        return Result.ok2Log(LogConstants.TRANSFER + dto.getName() + "至" + dto.getPhone());
    }
}
